package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.exception.CustomException;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.builder.ArticleDtoBuilder;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: xrl
 * @Date: 2022/10/17  17:12
 * @Version 1.0
 */
@Service
@Slf4j
@Transactional
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    /**
     * 自媒体文章审核
     *
     * @param id 自媒体文章id
     */
    @Override
    @Async  //标明当前方法是一个异步方法
    @GlobalTransactional  //分布式全局事务的方法入口
    public void autoScanWmNews(Integer id) {
        //1.根据文章的id查询文章
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null) {
            //文章数据不存在
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //当前状态为1(待审核),才进行审核步骤
        if (wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())) {
            //2.解析文章的内容数据 —— 所有的文本内容和图片
            Map<String, Object> textAndImages = handleTextAndImages(wmNews);

            //3.自定义的敏感词过滤审核
            boolean isSensitive = handleSensitiveScan((String) textAndImages.get("content"), wmNews);
            if (!isSensitive) {
                return;
            }

            //4.把文本内容上传到阿里云进行审核  —— 审核失败(文章状态为2)  人工审核(状态为3)
            boolean isTextScan = handleTextScan((String) textAndImages.get("content"), wmNews);
            if (!isTextScan) {
                //审核失败，就结束方法
                return;
            }
            //5.把所有图片上传到阿里云审核   —— 审核失败(文章状态为2)  人工审核(状态为3)
            boolean isImageScan = handleImageScan((List<String>) textAndImages.get("images"), wmNews);
            if (!isImageScan) {
                return;
            }
            //6.审核成功,同步文章数据到文章微服务
            ResponseResult result = saveAppArticle(wmNews);

            //判断同步是否成功
            if (!result.getCode().equals(200)) {
                throw new RuntimeException("WmNewsAutoScanServiceImpl-文章审核，保存app端相关文章数据失败");
            }

            //=====================自定义异常=============================
//            int a = 1 / 0;
            //==========================================================

            //7.更新文章的审核状态为9
            wmNews.setArticleId((Long) result.getData());
            updateWmNews(wmNews, (short) 9, "审核成功");
        }
    }

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    /**
     * 自定义的敏感词过滤审核
     *
     * @param content 图文内容
     * @param wmNews  自媒体图文内容信息
     * @return
     */
    private boolean handleSensitiveScan(String content, WmNews wmNews) {
        //假设初始审核状态为true
        boolean flag = Boolean.TRUE;
        //组装查询条件
        LambdaQueryWrapper<WmSensitive> wrapper = Wrappers.<WmSensitive>lambdaQuery()
                .select(WmSensitive::getSensitives);
        //查询获取所有的敏感词
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(wrapper);
        List<String> sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        //初始化敏感词库
        SensitiveWordUtil.initMap(sensitiveList);
        //查看文章中是否包含敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if (map.size() > 0) {
            //代表存在敏感词
            updateWmNews(wmNews, (short) 2, "当前文章中存在违规内容:" + map);
            flag = Boolean.FALSE;
        }
        return flag;
    }

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private WmUserMapper wmUserMapper;


    @Autowired
    private IArticleClient articleClient;

    /**
     * 保存app端相关的文章数据
     *
     * @param wmNews
     * @return
     */
    private ResponseResult saveAppArticle(WmNews wmNews) {
        ArticleDtoBuilder articleDtoBuilder = new ArticleDtoBuilder(wmNews, wmChannelMapper, wmUserMapper);
        //构建dto数据
        ArticleDto dto = articleDtoBuilder
                .buildBeanCopy()
                .buildAuthor()
                .buildChannel()
                .buildBasic()
                .builder();

        //远程调用保存app端文章内容接口
        ResponseResult result = articleClient.saveArticle(dto);
        return result;
    }

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private GreenImageScan imageScan;

    @Autowired
    private Tess4jClient tess4jClient;

    /**
     * 审核图片
     *
     * @param images 图片路径集合
     * @param wmNews 文章数据
     * @return
     */
    @SneakyThrows
    private boolean handleImageScan(List<String> images, WmNews wmNews) {
        //假设初始审核状态为true
        boolean flag = Boolean.TRUE;

        if (images == null || images.size() == 0) {
            return flag;
        }

        //下载所有的图片
        //图片去重
        images = images.stream().distinct().collect(Collectors.toList());
        //存储图片集合
        List<byte[]> imageList = new ArrayList<>();
        for (String image : images) {
            //下载图片
            byte[] bytes = fileStorageService.downLoadFile(image);

            //图片敏感词识别
            //从byte[]转换为butteredImage
            ByteArrayInputStream in = new ByteArrayInputStream(bytes);
            BufferedImage image1 = ImageIO.read(in);

            //提取图片中的文字
            String result = tess4jClient.doOCR(image1);
            //审核是否包含自管理的敏感词
            boolean isSensitive = handleSensitiveScan(result, wmNews);
            if (!isSensitive) {
                //代表存在敏感词,结束方法
                flag = Boolean.FALSE;
                return flag;
            }
            imageList.add(bytes);
        }

        //审核图片
        try {
            Map map = imageScan.imageScan(imageList);
            if (map != null) {
                if (map.get("suggestion").equals("block")) {
                    //代表审核失败,文章状态设为2
                    flag = Boolean.FALSE;
                    updateWmNews(wmNews, (short) 2, "当前图片中存在违规内容");
                }
                if (map.get("suggestion").equals("review")) {
                    //不确定信息  需要人工审核
                    flag = Boolean.FALSE;
                    updateWmNews(wmNews, (short) 3, "当前图片中存在不确定内容,需要人工审核");
                }
            }
        } catch (Exception e) {
            flag = Boolean.FALSE;
            e.printStackTrace();
        }
        return flag;
    }

    @Autowired
    private GreenTextScan textScan;

    /**
     * 审核纯文本内容
     *
     * @param content 文本内容
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {
        //假设审核状态为成功true
        boolean flag = true;

        if ((wmNews.getTitle() + "-" + content).length() == 0) {
            //标题及文本为空，审核成功返回
            return flag;
        }

        try {
            Map map = textScan.greeTextScan((wmNews.getTitle() + "-" + content));
            if (map != null) {
                //审核失败
                if (map.get("suggestion").equals("block")) {
                    //设置审核状态为失败false
                    flag = false;
                    updateWmNews(wmNews, (short) 2, "当前文章存在违规内容");
                }

                //文章具有不确定信息,需要人工审核
                if (map.get("suggestion").equals("review")) {
                    //设置审核状态为失败false
                    flag = false;
                    updateWmNews(wmNews, (short) 3, "当前文章存在不确定内容");
                }
            }
        } catch (Exception e) {
            //设置审核状态为失败false
            flag = false;
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 修改文章内容
     *
     * @param wmNews 文章
     * @param num    文章状态
     * @param str    拒绝理由
     */
    private void updateWmNews(WmNews wmNews, short num, String str) {
        wmNews.setStatus(num);
        wmNews.setReason(str);
        //调用方法修改文章
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 1.从自媒体文章的内容中提取文本和图片
     * 2.提取文章的封面图片
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        //存储纯文本内容
        StringBuilder stringBuilder = new StringBuilder();
        //存储图片路径
        List<String> images = new ArrayList<>();

        //1.从自媒体文章中提取纯文本和图片
        if (StringUtils.isNotBlank(wmNews.getContent())) {
            //转换为map
            List<Map> maps = JSONArray.parseArray(wmNews.getContent(), Map.class);
            for (Map map : maps) {
                if (map.get("type").equals("text")) {
                    //是文本
                    stringBuilder.append(map.get("value"));
                }

                if (map.get("type").equals("image")) {
                    //是图片路径
                    images.add((String) map.get("value"));
                }
            }
        }
        //2.提取文章的封面图片
        if (StringUtils.isNotBlank(wmNews.getImages())) {
            String[] split = wmNews.getImages().split(",");
            //批量添加到images
            images.addAll(Arrays.asList(split));
        }

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("content", stringBuilder.toString());
        resultMap.put("images", images);

        //返回结果
        return resultMap;
    }
}
